package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.dao.DishDao;
import com.itheima.dto.DishDto;
import com.itheima.entity.Category;
import com.itheima.entity.Dish;
import com.itheima.entity.DishFlavor;
import com.itheima.service.CategoryService;
import com.itheima.service.DishFlavorService;
import com.itheima.service.DishService;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Tang
 * @date 2023/4/12
 */
@Service
public class DishServiceImpl extends ServiceImpl<DishDao, Dish> implements DishService {
    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
//    @Lazy       //延迟加载
    private CategoryService categoryService;
    @Autowired
    private RedisTemplate redisTemplate;



    /**
     * 新增菜品信息包含口味
     * @param dishDto
     */
    @Override
    @Transactional
    public void addDishWithFalvors(DishDto dishDto) {
        //0.开启事务（涉及到多张表的增删改）
        //1.新增菜品基本信息到菜品表dish
        this.save(dishDto);

        //2.新增口味信息列表到口味表dish_flavor
        //2.1 循环口味列表，绑定菜品id
        List<DishFlavor> flavors = dishDto.getFlavors();
        for (DishFlavor flavor : flavors) {
            flavor.setDishId(dishDto.getId());
            dishFlavorService.save(flavor);
        }

       //新增菜品后清除缓存内对应分类的菜品信息保证数据一致性
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);

    }

    /**
     * 分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @Override
    public Page<DishDto> pageWithCategoryName(Integer page, Integer pageSize, String name) {

        //0.分页拦截器【已经完成】
        //1.调用service的分页方法
        //1.1 构造分页对象Page(page, pageSize)
        Page<Dish> dishPage = new Page<>(page, pageSize);

        //1.2 构造查询条件，菜品名称
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(name != null, Dish::getName, name);  //where name = null

        //1.3 调用service的分页方法
        this.page(dishPage, wrapper);

        //优化：
        //1.创建page对象，dishDtoPage = new Page<DishDto>()
        Page<DishDto> dishDtoPage = new Page<>();

        //2.封装dishDtoPage数据records、total、current、size
        //2.1 将dishPage里面所有属性复制到dishDtoPage中排除records属性
        BeanUtils.copyProperties(dishPage, dishDtoPage, "records");

        //2.2 需要单独封装records属性: List<DishDto>
        List<DishDto> dishDtos = new ArrayList<>();
        //2.3 通过dishPage对象中的records去封装 List<Dish>
        List<Dish> dishList = dishPage.getRecords();

        //2.4 循环遍历List<Dish>，将dish属性值全部复制到DishDto中
        for (Dish dish : dishList) {
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(dish, dishDto);
            //2.5 查询分类表，得到分类名称，封装到DishDto中
            Category category = categoryService.getById(dish.getCategoryId());
            dishDto.setCategoryName(category.getName());
            dishDtos.add(dishDto);
        }

        //3. 将records设置回到dishDtoPage对象中
        dishDtoPage.setRecords(dishDtos);

        return dishDtoPage;
    }

    /**
     * 查询菜品信息包含口味信息
     * @param id 菜品id
     * @return
     */
    @Override
    public DishDto getDishWithFlavors(Long id) {
        DishDto dishDto = new DishDto();

        //1.查询菜品表，将菜品信息封装到dishDto中
        Dish dish = this.getById(id);           //select * from dish where id = ?;
        BeanUtils.copyProperties(dish, dishDto);

        //2.查询菜品口味表，将菜品口味信息封装到dishDto中
        LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DishFlavor::getDishId, id);  //select * from dish_flavor where dish_id = ?;
        List<DishFlavor> dishFlavors = dishFlavorService.list(wrapper);
        dishDto.setFlavors(dishFlavors);

        //3.返回dishDto
        return dishDto;
    }

    /**
     * 修改菜品包含口味修改
     * @param dishDto
     */
    @Override
    public void updateWithFlavor(DishDto dishDto) {
        Long newCategoryId = dishDto.getCategoryId();
        Dish dish = this.getById(dishDto.getId());
        Long oldCategoryId = dish.getCategoryId();
        //0.开启事务（涉及到多表更新）
        //1.调用自身的更新方法，修改dish表
        this.updateById(dishDto);

        //2.修改口味表
        //2.1 删除掉原来的口味信息
        LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DishFlavor::getDishId, dishDto.getId());
        dishFlavorService.remove(wrapper);

        //2.2 将前端传递过来的口味列表数据保存到dish_flavor中
        List<DishFlavor> flavors = dishDto.getFlavors();
        //2.3 遍历口味列表，绑定菜品id
        for (DishFlavor flavor : flavors) {
            flavor.setDishId(dishDto.getId());
            //如果开启了逻辑删除，需要将id置null
            flavor.setId(null);
        }
        //3.调用dishFlavorService的新增方法
        dishFlavorService.saveBatch(flavors);
        if (oldCategoryId!=newCategoryId){
            //如果修改分类则还需要清理之前的分类缓存
            redisTemplate.delete("dish_"+oldCategoryId+"_"+dishDto.getStatus());
        }
        //如果没有修改分类只需要清理当前的分类缓存
        redisTemplate.delete("dish_"+newCategoryId+"_"+dishDto.getStatus());
    }

    /**
     * 查询菜品列表数据包含口味数据
     * @param dish
     * @return
     */
    @Override
    public List<DishDto> listWithFlavors(Dish dish) {
        String key = "dish_"+ dish.getCategoryId()+"_"+ dish.getStatus();
        List<DishDto> dishDtoList = (List) redisTemplate.opsForValue().get(key);
        if (dishDtoList!=null){
            return dishDtoList;
        }

        //1.创建条件对象，构造查询条件
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
        wrapper.like(dish.getName() != null, Dish::getName, dish.getName());
        wrapper.eq(dish.getStatus() != null, Dish::getStatus, dish.getStatus());

        //2.查询dish列表信息（根据分类id和状态）,得到List<Dish>
        List<Dish> dishList = this.list(wrapper);

        //3.封装List<DishDto>
        List<DishDto> dishDtos = new ArrayList<>();

        //4.循环遍历List<Dish>，将dish数据拷贝给dishDto
        for (Dish dish1 : dishList) {
            DishDto dishDto = new DishDto();
            //封装菜品数据
            BeanUtils.copyProperties(dish1, dishDto);
            //5.查询口味表（根据菜品id），得到口味列表数据,封装给dishDto
            LambdaQueryWrapper<DishFlavor> flavorWrapper = new LambdaQueryWrapper<>();
            flavorWrapper.eq(DishFlavor::getDishId, dish1.getId());
            List<DishFlavor> flavors = dishFlavorService.list(flavorWrapper);
            dishDto.setFlavors(flavors);
            //6.将dishDto添加到List<DishDto>
            dishDtos.add(dishDto);
        }

        redisTemplate.opsForValue().set(key,dishDtos);

        //7.返回List<DishDto>
        return dishDtos;
    }

    /**
     * 批量修改
     * @param id
     * @param ids
     */
    @Override
    public void state(Integer id, List ids) {
        //构造条件
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
       queryWrapper.in(Dish::getId,ids);
        List<Dish> dishList = this.list(queryWrapper);
        List<Dish> collect = dishList.stream().map((item) -> {
            item.setStatus(id);
            return item;
        }).collect(Collectors.toList());
       updateBatchById(collect);
        //批量更改菜品状态的时候也要将缓存的所有菜品删除 保持重新查询数据库数据再缓存 保存数据一致
        Set keys = redisTemplate.keys("dish_*");
        redisTemplate.delete(keys);
    }


}
